/*@author Sam SmithReams*/

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Scanner;

import org.teleal.cling.UpnpService;
import org.teleal.cling.UpnpServiceImpl;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.Device;
import org.teleal.cling.model.meta.LocalDevice;
import org.teleal.cling.model.meta.RemoteDevice;
import org.teleal.cling.model.types.UDAServiceId;
import org.teleal.cling.registry.Registry;
import org.teleal.cling.registry.RegistryListener;
import org.teleal.cling.support.avtransport.callback.Play;
import org.teleal.cling.support.avtransport.callback.SetAVTransportURI;
import org.teleal.cling.support.model.DIDLContent;
import org.teleal.cling.support.model.DIDLObject.Property;

public class ClingBrowse
{

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		RegistryListener listener = new RegistryListener()
		{
			public void remoteDeviceDiscoveryStarted(Registry registry,
					RemoteDevice device)
			{
//				System.out.println("Discovery started: "
//						+ device.getDisplayString());
			}

			public void remoteDeviceDiscoveryFailed(Registry registry,
					RemoteDevice device, Exception ex)
			{
//				System.out.println("Discovery failed: "
//						+ device.getDisplayString() + " => " + ex);
			}

			public void remoteDeviceAdded(Registry registry, RemoteDevice device)
			{
//				System.out.println("Device found: "
//						+ device.getDisplayString());
			}

			public void remoteDeviceUpdated(Registry registry,
					RemoteDevice device)
			{
//				System.out.println("Remote device updated: "
//						+ device.getDisplayString());
			}

			public void remoteDeviceRemoved(Registry registry,
					RemoteDevice device)
			{
//				System.out.println("Remote device removed: "
//						+ device.getDisplayString());
			}

			public void localDeviceAdded(Registry registry, LocalDevice device)
			{
//				System.out.println("Local device added: "
//						+ device.getDisplayString());
			}

			public void localDeviceRemoved(Registry registry, LocalDevice device)
			{
//				System.out.println("Local device removed: "
//						+ device.getDisplayString());
			}

			public void beforeShutdown(Registry registry)
			{
				System.out
						.println("Before shutdown, the registry has devices: "
								+ registry.getDevices().size());
			}

			public void afterShutdown()
			{
				System.out.println("Shutdown of registry complete!");

			}
		};
		
		try
		{
			System.setErr(new PrintStream(new FileOutputStream("std_err.txt")));
		} catch (FileNotFoundException e1)
		{
			System.out.println("Unable to redirect std err");
		}
		
		Scanner scanner = new Scanner(System.in);
		// This will create necessary network resources for UPnP right away
        System.out.println("Starting Cling...");
        UpnpService upnpService = new UpnpServiceImpl(listener);

        // Send a search message to all devices and services, they should respond soon
        upnpService.getControlPoint().search(new MediaServerTypeHeader());
        upnpService.getControlPoint().search(new MediaRendererTypeHeader());
        
        Device server = null, renderer = null;
        boolean found = false;
        while(!found)
        {
	        try
			{
				Thread.sleep(1000);
			} 
	        catch (InterruptedException e)
			{
				e.printStackTrace();
			}
	        
	        for(Device d : upnpService.getRegistry().getDevices())
	        {
//	        	System.out.println(d.getType().getDisplayString() + ":" + d.getDisplayString());
	        	if(server == null && d.getDisplayString().contains("TVersity"))
	        	{
		        	server = d;
		        	System.out.println("Server Found: " + d.getDisplayString());
	        	}
	        	
	        	if(renderer == null && d.getDisplayString().contains("XBMC 2.0"))
	        	{
	        		renderer = d;
	        		System.out.println("Renderer Found: " + d.getDisplayString());
	        	}
	        	
	        	if(server != null && renderer != null)
	        		found = true;
	        }
        }
        
        upnpService.getRegistry().pause();
        
//        System.out.println("Select a server");
        
//        int counter = 0;
//        ServiceId serviceId = new UDAServiceId("ContentDirectory");
//        List<Device> devices = new ArrayList<Device>();
//        for(Device device : upnpService.getRegistry().getDevices())
//        {
//			Service<?,?> s = device.findService(serviceId);
//        	if(s != null)
//        	{
//        		counter++;
//        		devices.add(device);
////        		if(device.isFullyHydrated())
////        			System.out.print("(Fully Hydrated)");
//        		System.out.println(counter + ": " + device.getDisplayString());
//        	}
//        }
        
//        Scanner scanner = new Scanner(System.in);
//        int choice = scanner.nextInt();
//        
//        Device chosenDevice = devices.get(choice - 1);
//        Service<?,?> contDir = chosenDevice.findService(serviceId);
        
//        SearchCapabilities searchCaps = new SearchCapabilities(contDir);
//        upnpService.getControlPoint().execute(searchCaps);
//        try
//		{
//			Thread.sleep(2000);
//		} 
//        catch (InterruptedException e)
//		{
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//        
//        System.out.println("Search Capabilities-");
//        for(String prop : searchCaps.getPropertyNames())
//        {
//        	System.out.println(prop);
//        }
//
//        SortCapabilities sortCaps = new SortCapabilities(contDir);
//        upnpService.getControlPoint().execute(sortCaps);
//        try
//		{
//			Thread.sleep(2000);
//		} 
//        catch (InterruptedException e)
//		{
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//        
//        System.out.println("Sort Capabilities-");
//        for(String tag : sortCaps.getTagNames())
//        {
//        	System.out.println(tag);
//        }

        SearchCriteria searchCriteria = new SearchCriteria();
        searchCriteria.addSearchItem(new MusicSearchItem());
        searchCriteria.addSearchItem(new MovieSearchItem());
        searchCriteria.addSearchItem(new PhotoSearchItem());
        searchCriteria.addSearchItem(new VideoSearchItem());
        
        System.out.print("Search for? ");        
        searchCriteria.setProperty(SearchProperty.Type.TITLE, scanner.next());
        final SearchInfo info = new SearchInfo();
        
        Search search = new Search(server.findService(new UDAServiceId("ContentDirectory")), "0", searchCriteria, info)
        {

			@Override
			public void received(ActionInvocation actionInvocation,
					DIDLContent didl)
			{
				System.out.println("Items returned- " + didl.getItems().size());
				
				System.out.println("Results-");
				for(int i = 0; i < didl.getItems().size(); i++)
				{
					System.out.println(i + "-");
					System.out.println("title- " + didl.getItems().get(i).getTitle());
					System.out.println("type= " + didl.getItems().get(i).getClazz().getValue().substring(12));
					for(Property property : didl.getItems().get(i).getProperties())
					{
						if(property.getDescriptorName().equals("artist") || property.getDescriptorName().equals("album") || 
								property.getDescriptorName().equals("genre"))
						System.out.println(property.getDescriptorName() + "- " + property.getValue());
					}
				}				
			}

			@Override
			public void updateStatus(Status status)
			{
				//Do nothing
				
			}

			@Override
			public void failure(ActionInvocation invocation,
					UpnpResponse operation, String defaultMsg)
			{
				System.out.println(defaultMsg);
				
			}
        	
        };
        
        upnpService.getControlPoint().execute(search);
        
        while(!info.isDone())
	        try
			{
				Thread.sleep(1000);
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
        
        System.out.print("Choice? ");
        if(scanner.hasNextLine())
        	scanner.nextLine();
        int choice = scanner.nextInt();
        
        upnpService.getControlPoint().execute(new SetAVTransportURI(renderer.findService(new UDAServiceId("AVTransport")), info.getResInfo().get(choice))
        {

			@Override
			public void failure(ActionInvocation invocation,
					UpnpResponse operation, String defaultMsg)
			{
				System.out.println("SetAVTransportURI failed");
				
			}
        	
        });
        
        try
		{
			Thread.sleep(10000);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
		}
        
        upnpService.getControlPoint().execute(new Play(renderer.findService(new UDAServiceId("AVTransport")))
        {

			@Override
			public void failure(ActionInvocation invocation,
					UpnpResponse operation, String defaultMsg)
			{
				System.out.println("Play failed");
			}
        	
        });
        
        try
		{
			Thread.sleep(10000);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
		}
        // Release all resources and advertise BYEBYE to other UPnP devices
        System.out.println("Stopping Cling...");
        upnpService.shutdown();

	}

}
